/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.iec.edp.caf.caching.manager;

import io.iec.edp.caf.caching.api.Cache;
import io.iec.edp.caf.caching.cache.LayeringCache;
import io.iec.edp.caf.caching.cache.caffeine.CaffeineCache;
import io.iec.edp.caf.caching.cache.redis.RedisCache;
import io.iec.edp.caf.caching.properties.CacheSetting;
import io.iec.edp.caf.caching.properties.JedisPoolConfigProperties;
import io.iec.edp.caf.caching.properties.RedisCacheProperties;
import io.iec.edp.caf.caching.setting.LayeringCacheSetting;
import io.iec.edp.caf.commons.runtime.CafEnvironment;
import org.springframework.util.Assert;

/**
 * 缓存管理器
 *
 * @author guowenchang
 * @date 2020-04-28
 */
public class LayeringCacheManager extends AbstractCacheManager {
    private RedisCacheProperties settings;
    private RedisClientManager redisClientManager;
    private Boolean enableRedis = null;

    public LayeringCacheManager(RedisCacheProperties redisCacheSettings, JedisPoolConfigProperties jedisPoolConfigProperties) {
        this.settings = redisCacheSettings;
        this.enableRedis = CafEnvironment.getEnvironment().getProperty("redis.enabled", Boolean.class, true);
        if (this.enableRedis) this.redisClientManager = new RedisClientManager(jedisPoolConfigProperties, settings);
        cacheManagers.add(this);
    }

    @Override
    protected Cache getMissingCache(String name, LayeringCacheSetting setting) {
        setting.setUseSecondCache(setting.isUseSecondCache() && enableRedis);
        setting.setUseFirstCache(setting.isUseFirstCache() || (!enableRedis));
        Assert.isTrue(setting.isUseFirstCache() || setting.isUseSecondCache(), "Please insure at least one level cache is enabled");

        // 创建一级缓存
        CaffeineCache caffeineCache = setting.isUseFirstCache() ? new CaffeineCache(name, setting.getFirstCacheSetting(), getStats(), setting.isAllowNullValue()) : null;

        if (setting.isUseSecondCache()) {
            // 创建二级缓存
            RedisClient redisClient = getOrDefaultRedisClient(name);
            RedisCache redisCache = new RedisCache(name, redisClient.redisTemplate, setting.getSecondaryCacheSetting(), getStats(), setting.isAllowNullValue());
            this.redisClientPool.put(name, redisClient);
            return new LayeringCache(redisClient.redisTemplate, caffeineCache, redisCache, super.getStats(), setting);
        } else {
            return new LayeringCache(null, caffeineCache, null, setting.isUseFirstCache(), setting.isUseSecondCache(), super.getStats(), name, setting);
        }
    }

    @Override
    protected boolean useFirstAndSecond(LayeringCacheSetting setting) {
        return setting.isUseFirstCache() && setting.isUseSecondCache();
    }

    private RedisClient getOrDefaultRedisClient(String name) {
        CacheSetting cacheSetting = this.settings.getCacheConfig(name);
        if (cacheSetting == null) {
            cacheSetting = this.settings.getCacheConfig("default");
        }

        if (cacheSetting == null) {
            throw new RuntimeException("The setting with the name [default] under node [caching-configuration] in the [application.yaml] does not exist, Please keep the node with the name [default]");
        }

        return this.redisClientManager.getRedisClient(cacheSetting);
    }

    @Override
    public boolean equals(Object o) {
        return super.equals(o);
    }

    @Override
    public int hashCode() {
        return super.hashCode();
    }
}
